import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:built_collection/built_collection.dart';
import 'package:mobile_app.core/core/domain/entities/settings/image_settings.dart';
import 'package:mobile_app.core/core/domain/entities/learning_content/collection_list_item/collection_list_item.dart';
import 'package:mobile_app.core/learning_content/application/bloc/bloc.dart';
import 'package:mobile_app.core/purchase_flow_display/application/bloc.dart';
import 'package:mobile_app.core/settings/application/bloc/bloc.dart';
import 'package:mobile_app.core/user_info/application/bloc/bloc.dart';
import 'package:mobile_app.home.menu.settings/image_settings_page/domain/use_cases/clear_image_cache/use_case.dart';
import 'package:mobile_app.home.menu.settings/image_settings_page/domain/use_cases/download_all_images/use_case.dart';
import 'package:mobile_app.home.menu.settings/image_settings_page/domain/use_cases/download_collection_images/use_case.dart';
import 'package:mobile_app.home.menu.settings/image_settings_page/domain/use_cases/get_initial_data/use_case.dart';
import 'package:mobile_app.home.menu.settings/image_settings_page/domain/use_cases/handle_cached_image_path_map_outer_update/use_case.dart';
import 'package:mobile_app.home.menu.settings/image_settings_page/domain/use_cases/handle_download_task_id_outer_update/use_case.dart';
import 'package:mobile_app.home.menu.settings/image_settings_page/domain/use_cases/handle_learning_content_outer_update/use_case.dart';
import 'package:mobile_app.home.menu.settings/image_settings_page/domain/use_cases/handle_premium_access_status_outer_update/use_case.dart';
import 'package:mobile_app.home.menu.settings/image_settings_page/domain/use_cases/initialize/use_case.dart';
import 'package:mobile_app.home.menu.settings/image_settings_page/domain/use_cases/stop_all_image_download/use_case.dart';
import 'package:mobile_app.home.menu.settings/image_settings_page/domain/use_cases/stop_collection_image_download/use_case.dart';
import 'package:mobile_app.home.menu.settings/image_settings_page/domain/use_cases/toggle_image_enablement/use_case.dart';

part 'bloc_state.dart';

class ImageSettingsPageBloc extends Cubit<ImageSettingsPageBlocState> {
  ImageSettingsPageBloc({
    required LearningContentBloc learningContentBloc,
    required SettingsBloc settingsBloc,
    required UserInfoBloc userInfoBloc,
    required PurchaseFlowDisplayBloc purchaseFlowDisplayBloc,
    required GetInitialData getInitialData,
    required Initialize initialize,
    required ClearImageCache clearImageCache,
    required DownloadCollectionImages downloadCollectionImages,
    required DownloadAllImages downloadAllImages,
    required HandleCachedImagePathMapOuterUpdate handleCachedImagePathMapOuterUpdate,
    required HandleLearningContentOuterUpdate handleLearningContentOuterUpdate,
    required HandleDownloadTaskIdOuterUpdate handleDownloadTaskIdOuterUpdate,
    required HandlePremiumAccessStatusOuterUpdate handlePremiumAccessStatusOuterUpdate,
    required StopAllImageDownload stopAllImageDownload,
    required StopCollectionImageDownload stopCollectionImageDownload,
    required ToggleImageEnablement toggleImageEnablement,
  })  : _learningContentBloc = learningContentBloc,
        _settingsBloc = settingsBloc,
        _purchaseFlowDisplayBloc = purchaseFlowDisplayBloc,
        _clearImageCache = clearImageCache,
        _downloadCollectionImages = downloadCollectionImages,
        _downloadAllImages = downloadAllImages,
        _handleCachedImagePathMapOuterUpdate = handleCachedImagePathMapOuterUpdate,
        _handleLearningContentOuterUpdate = handleLearningContentOuterUpdate,
        _handleDownloadTaskIdOuterUpdate = handleDownloadTaskIdOuterUpdate,
        _handlePremiumAccessStatusOuterUpdate = handlePremiumAccessStatusOuterUpdate,
        _stopAllImageDownload = stopAllImageDownload,
        _stopCollectionImageDownload = stopCollectionImageDownload,
        _toggleImageEnablement = toggleImageEnablement,
        super(_getIntitialState(
          learningContentBlocState: learningContentBloc.state!,
          settingsBlocState: settingsBloc.state!,
          getInitialData: getInitialData,
        )) {
    final initializationResult = initialize();

    _cacheSizeInBytesStreamSubscription =
        initializationResult.cacheSizeInBytesStream.listen(_onCacheSizeInBytesChanged);

    _cachedImagePathMapStreamSubscription =
        initializationResult.cachedImagePathMapStream.listen(_onCachedImagePathMapChanged);

    _downloadTaskIdStreamSubscription =
        initializationResult.downloadTaskIdStream.listen(_onDownloadTaskIdsChanged);

    _learningContentBlocSubscription =
        learningContentBloc.stream.listen(_onLearningContentBlocStateChanged);

    _settingsBlocSubscription = settingsBloc.stream.listen(_onSettingsBlocStateChanged);

    _userInfoBlocSubscription = userInfoBloc.streamWithPrevious.listen(_onUserInfoBlocStateChanged);
  }

  final LearningContentBloc _learningContentBloc;
  final SettingsBloc _settingsBloc;
  final PurchaseFlowDisplayBloc _purchaseFlowDisplayBloc;

  final ClearImageCache _clearImageCache;
  final DownloadCollectionImages _downloadCollectionImages;
  final DownloadAllImages _downloadAllImages;
  final HandleCachedImagePathMapOuterUpdate _handleCachedImagePathMapOuterUpdate;
  final HandleLearningContentOuterUpdate _handleLearningContentOuterUpdate;
  final HandleDownloadTaskIdOuterUpdate _handleDownloadTaskIdOuterUpdate;
  final HandlePremiumAccessStatusOuterUpdate _handlePremiumAccessStatusOuterUpdate;
  final StopAllImageDownload _stopAllImageDownload;
  final StopCollectionImageDownload _stopCollectionImageDownload;
  final ToggleImageEnablement _toggleImageEnablement;

  late final StreamSubscription<int> _cacheSizeInBytesStreamSubscription;
  late final StreamSubscription<BuiltMap<String, String>> _cachedImagePathMapStreamSubscription;
  late final StreamSubscription<BuiltSet<String>> _downloadTaskIdStreamSubscription;
  late final StreamSubscription<LearningContentBlocState> _learningContentBlocSubscription;
  late final StreamSubscription<SettingsBlocState> _settingsBlocSubscription;
  late final StreamSubscription<(UserInfoBlocState, UserInfoBlocState?)> _userInfoBlocSubscription;

  static ImageSettingsPageBlocState _getIntitialState({
    required LearningContentBlocState learningContentBlocState,
    required SettingsBlocState settingsBlocState,
    required GetInitialData getInitialData,
  }) {
    final result = getInitialData(
      lexicalItemMap: learningContentBlocState.lexicalItemMap,
      collectionListItems: learningContentBlocState.collectionListItems,
    );

    return ImageSettingsPageBlocState(
      collectionListItems: learningContentBlocState.collectionListItems,
      imageDownloadingCollectionIds: result.imageDownloadingCollectionIds,
      collectionImageCacheRatioMap: result.collectionImageCacheRatioMap,
      allImagesDownloading: result.allImagesDownloading,
      allImageCacheRatio: result.allImageCacheRatio,
      cacheSizeInBytes: result.cacheSizeInBytes,
      imageSettings: settingsBlocState.imageSettings,
    );
  }

  void _onCacheSizeInBytesChanged(int cacheSizeInBytes) {
    emit(state.copyWith(
      cacheSizeInBytes: () => cacheSizeInBytes,
    ));
  }

  void _onCachedImagePathMapChanged(BuiltMap<String, String> cachedImagePathMap) {
    final result = _handleCachedImagePathMapOuterUpdate(
      cachedImagePathMap: cachedImagePathMap,
      collectionListItems: state.collectionListItems,
      lexicalItemMap: _learningContentBloc.state!.lexicalItemMap,
    );

    emit(state.copyWith(
      allImageCacheRatio: () => result.allImageCacheRatio,
      collectionImageCacheRatioMap: () => result.collectionImageCacheRatioMap,
    ));
  }

  void _onDownloadTaskIdsChanged(BuiltSet<String> downloadTaskIds) {
    final result = _handleDownloadTaskIdOuterUpdate(
      downloadTaskIds: downloadTaskIds,
      collectionListItems: state.collectionListItems,
      lexicalItemMap: _learningContentBloc.state!.lexicalItemMap,
    );

    emit(state.copyWith(
      allImagesDownloading: () => result.allImagesDownloading,
      imageDownloadingCollectionIds: () => result.imageDownloadingCollectionIds,
    ));
  }

  void _onLearningContentBlocStateChanged(LearningContentBlocState learningContentBlocState) {
    final result = _handleLearningContentOuterUpdate(
      lexicalItemMap: learningContentBlocState.lexicalItemMap,
      collectionListItems: learningContentBlocState.collectionListItems,
    );

    emit(state.copyWith(
      collectionListItems: () => learningContentBlocState.collectionListItems,
      imageDownloadingCollectionIds: () => result.imageDownloadingCollectionIds,
      allImageCacheRatio: () => result.allImageCacheRatio,
      collectionImageCacheRatioMap: () => result.collectionImageCacheRatioMap,
    ));
  }

  void _onSettingsBlocStateChanged(SettingsBlocState settingsBlocState) {
    if (state.imageSettings == settingsBlocState.imageSettings) {
      return;
    }

    emit(state.copyWith(
      imageSettings: () => settingsBlocState.imageSettings,
    ));
  }

  void _onUserInfoBlocStateChanged((UserInfoBlocState, UserInfoBlocState?) valueWithPrevious) {
    final (userInfoBlocState, userInfoBlocPreviousState) = valueWithPrevious;

    if (userInfoBlocState.premiumAccessStatus == userInfoBlocPreviousState!.premiumAccessStatus) {
      return;
    }

    final result = _handlePremiumAccessStatusOuterUpdate(
      imageSettings: state.imageSettings,
      premiumAccessStatus: userInfoBlocState.premiumAccessStatus,
    );

    emit(state.copyWith(
      imageSettings: () => result.imageSettings,
    ));
  }

  void requestImageEnablementToggling() {
    if (!state.imageSettings.imageEnablementChangePermitted) {
      _purchaseFlowDisplayBloc.openPurchasePage();
      return;
    }

    final result = _toggleImageEnablement(
      imageSettings: state.imageSettings,
    );

    emit(state.copyWith(
      imageSettings: () => result.imageSettings,
    ));

    _settingsBloc.updateImageSettingsData(
      imageSettingsData: result.imageSettingsData,
    );
  }

  void requestAllImageDownload() {
    _downloadAllImages(
      lexicalItemMap: _learningContentBloc.state!.lexicalItemMap,
    );
  }

  void requestAllImageDownloadStop() {
    _stopAllImageDownload();
  }

  void requestCollectionImageDownload({
    required String collectionId,
  }) {
    _downloadCollectionImages(
      collectionId: collectionId,
      collectionListItems: state.collectionListItems,
      lexicalItemMap: _learningContentBloc.state!.lexicalItemMap,
    );
  }

  void requestCollectionImageDownloadStop({
    required String collectionId,
  }) {
    _stopCollectionImageDownload(
      collectionId: collectionId,
    );
  }

  void requestImageCacheClearance() {
    _clearImageCache(
      allImagesDownloading: state.allImagesDownloading,
      imageDownloadingCollectionIds: state.imageDownloadingCollectionIds,
    );
  }

  @override
  Future<void> close() {
    _cacheSizeInBytesStreamSubscription.cancel();
    _cachedImagePathMapStreamSubscription.cancel();
    _downloadTaskIdStreamSubscription.cancel();
    _learningContentBlocSubscription.cancel();
    _settingsBlocSubscription.cancel();
    _userInfoBlocSubscription.cancel();

    return super.close();
  }
}
